<!--
 * 日历
 * @作者: 陈老师儿~
 * @手机: 18560000860
 -->
<template>
    <view class="pure-calendar" :class="classes" :style="styles" v-if="isShow">
        <!-- Overlay -->
        <pure-overlay :show="show && poppable && overlay" @close="handleOverlayClose"></pure-overlay>

        <!-- Dialog -->
        <view class="pure-calendar-dialog" @transitionend="handleTransitionEnd">
            <!-- Close -->
            <view class="pure-calendar-close" v-if="close && poppable" :hover-class="hoverClass" @tap="handleClose">
                <slot name="close" v-if="$slots.close"></slot>
                <pure-icon :name="closeIcon" v-else></pure-icon>
            </view>

            <!-- Header -->
            <view class="pure-calendar-header">
                <!-- Title -->
                <slot v-if="$slots.title"></slot>
                <view class="pure-calendar-header-title" v-else-if="title">{{ title }}</view>

                <!-- 切换器 -->
                <view class="pure-calendar-switch" v-if="switchMode !== 'none' || subtitle">
                    <!-- 上年 -->
                    <view
                        class="pure-calendar-switch-btn pure-calendar-switch-prev pure-calendar-switch-prev-year"
                        :hover-class="hoverClass"
                        @tap="handlePrevYear"
                        :class="[disabledPrevYear ? 'pure-calendar-switch-btn-disabled' : '']"
                        v-if="showYearSwitcher"
                    >
                        <pure-icon :name="yearPrevIcon"></pure-icon>
                    </view>

                    <!-- 上月 -->
                    <view
                        class="pure-calendar-switch-btn pure-calendar-switch-prev pure-calendar-switch-prev-month"
                        :hover-class="hoverClass"
                        @tap="handlePrevMonth"
                        :class="[disabledPrevMonth ? 'pure-calendar-switch-btn-disabled' : '']"
                        v-if="showMonthSwitcher"
                    >
                        <pure-icon :name="monthPrevIcon"></pure-icon>
                    </view>

                    <!-- 年月 -->
                    <view class="pure-calendar-year-month">{{ getSubtitle(yearMonth) }}</view>

                    <!-- 下月 -->
                    <view
                        class="pure-calendar-switch-btn pure-calendar-switch-next pure-calendar-switch-next-month"
                        :class="[disabledNextMonth ? 'pure-calendar-switch-btn-disabled' : '']"
                        :hover-class="hoverClass"
                        @tap="handleNextMonth"
                        v-if="showMonthSwitcher"
                    >
                        <pure-icon :name="monthNextIcon"></pure-icon>
                    </view>

                    <!-- 下年 -->
                    <view
                        class="pure-calendar-switch-btn pure-calendar-switch-next pure-calendar-switch-next-year"
                        :hover-class="hoverClass"
                        @tap="handleNextYear"
                        :class="[disabledNextYear ? 'pure-calendar-switch-btn-disabled' : '']"
                        v-if="showYearSwitcher"
                    >
                        <pure-icon :name="yearNextIcon"></pure-icon>
                    </view>
                </view>
            </view>

            <!-- Week -->
            <view class="pure-calendar-week">
                <slot v-if="$slots.week"></slot>
                <template v-else>
                    <view class="pure-calendar-week-item" v-for="item in weekOrder" :key="item">{{ item }}</view>
                </template>
            </view>

            <!-- Body -->
            <view class="pure-calendar-body">
                <scroll-view class="pure-calendar-scroll-view" :id="scrollViewId" scroll-y :scroll-top="scrollToTop" @scroll="handleScroll">
                    <view class="pure-calendar-scroll-view-content" :id="scrollContentId">
                        <!-- Month 月 -->
                        <view class="pure-calendar-month-wrapper" v-for="_month in months" :key="_month?.str">
                            <view class="pure-calendar-month">
                                <view class="pure-calendar-month-watermark" v-if="watermark">{{ getWatermark(_month) }} </view>
                                <view class="pure-calendar-month-header">{{ getMonthTitle(_month) }}</view>
                                <view class="pure-calendar-month-grid">
                                    <view class="pure-calendar-day pure-calendar-day-fill" :class="day?.classes" v-for="day in _month?.beforeDays" :key="day?.str" :hover-class="hoverClass">
                                        <rich-text class="pure-calendar-day-content" :nodes="getDay(day)"></rich-text>
                                    </view>
                                    <view class="pure-calendar-day" @tap="dayClick(day)" :class="day?.classes" v-for="day in _month?.days" :key="day?.str" :hover-class="hoverClass">
                                        <rich-text class="pure-calendar-day-content" :nodes="getDay(day)"></rich-text>
                                    </view>
                                    <view class="pure-calendar-day pure-calendar-day-fill" :class="day?.classes" v-for="day in _month?.afterDays" :key="day?.str" :hover-class="hoverClass">
                                        <rich-text class="pure-calendar-day-content" :nodes="getDay(day)"></rich-text>
                                    </view>
                                </view>
                            </view>
                        </view>
                    </view>
                </scroll-view>
            </view>

            <!-- Footer -->
            <view class="pure-calendar-footer" v-if="footer">
                <slot v-if="$slots.footer"></slot>
                <template v-else>
                    <pure-button :class="btnClass" :text="btnText" v-bind="btnOpts" @onClick="handleConfirm"></pure-button>
                </template>
            </view>
        </view>
    </view>
</template>

<script>
    import props from "./props.js";
    import { computed } from "vue";
    export default {
        options: {
            // 将自定义节点设置成虚拟的
            // 头条、飞书：因为合并后丢失事件和 'provide/inject'
            // 京东：因为合并后不能合并外层 'class'
            // 百度：因为合并后会在控制台疯狂报警告
            // #ifndef MP-TOUTIAO || MP-LARK || MP-JD || MP-BAIDU
            virtualHost: true,
            // #endif

            // 组件样式隔离
            styleIsolation: "apply-shared",

            // 允许使用多个插槽
            multipleSlots: true,
        },
        props: props,
        emits: ["change", "close", "confirm", "outMaxRange"],
        data() {
            return {
                // IDs
                scrollViewId: "",
                scrollContentId: "",

                // 数据
                days: [],
                // 区间范围
                range: [],
                // 当前展示的年月
                yearMonth: {
                    date: null,
                    year: "",
                    month: "",
                    str: "",
                },
                // 滚动距离
                scrollToTop: 0,
                scrollTop: 0,
                // 滚动视图的布局信息
                scrollViewRect: null,
                // 滚动内容的布局信息
                scrollContentRect: null,
                // 月布局信息
                monthRects: [],
                // 是否正在计算年月
                isComputing: false,
                // 是否需要在计算完后更新计算
                isNeedCompteNext: false,
                // 显示状态
                status: "hide",
                isShow: false,
            };
        },

        computed: {
            // classes
            classes() {
                const classes = [];

                // 显示状态类名
                classes.push(`pure-calendar-${this.status}`);

                // 是否弹窗
                if (this.poppable) classes.push("pure-calendar-poppable");

                // 显示安全区
                if (this.safeBottom) classes.push("pure-calendar-safe-bottom");

                return classes;
            },

            // styles
            styles() {
                const styles = [];
                return styles;
            },

            // 格式化后的开始日期
            fmtStartDate() {
                return this.formatDate(this.startDate);
            },

            // 格式化后的结束日期
            fmtEndDate() {
                return this.formatDate(this.endDate);
            },

            // 格式化后的默认日期
            fmtDefaultDate() {
                const dates = [];

                // Function
                if (typeof this.defaultDate === "function") {
                    const date = this.formatDate(this.defaultDate());
                    dates.push(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
                    return dates;
                }

                // Array
                if (Array.isArray(this.defaultDate)) {
                    this.defaultDate.forEach((_date) => {
                        const date = this.formatDate(_date);
                        dates.push(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
                    });
                    return dates;
                }

                // 未设置
                if (this.defaultDate === null || this.defaultDate === undefined) return dates;

                const date = this.formatDate(this.defaultDate);
                dates.push(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
                return dates;
            },

            // 格式化后的禁用日期
            fmtDisabledDate() {
                const dates = [];

                // Function
                if (typeof this.disabledDate === "function") {
                    const date = this.formatDate(this.disabledDate());
                    dates.push(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
                    return dates;
                }

                // Array
                if (Array.isArray(this.disabledDate)) {
                    this.disabledDate.forEach((_date) => {
                        const date = this.formatDate(_date);
                        dates.push(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
                    });
                    return dates;
                }

                // 未设置
                if (this.disabledDate === null || this.disabledDate === undefined) return dates;

                const date = this.formatDate(this.disabledDate);
                dates.push(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
                return dates;
            },

            // 月
            months() {
                // 按月份分组
                let _months = {};
                this.days.forEach((day) => {
                    let yearMonth = `${day.year}-${day.month}`;
                    if (!_months[yearMonth]) {
                        _months[yearMonth] = {
                            year: day.year,
                            month: day.month,
                            days: [day],
                            str: `${day.year}-${day.month}`,
                            date: new Date(day.year, day.month - 1),
                        };
                    } else {
                        _months[yearMonth].days.push(day);
                    }
                });

                // 每月第一天前面和后面需要填充的格子
                for (let key in _months) {
                    let month = _months[key];
                    let firstDay = month.days[0];
                    let lastDay = month.days[month.days.length - 1];

                    // 需要补齐的格子数
                    let beforeCount = firstDay.week - this.firstDayOfWeek;
                    let afterCount = 6 - lastDay.week;

                    // 补齐前面的格子
                    month.beforeDays = this.fillBeforeDays(month.days[0], beforeCount);

                    // 补齐后面的格子
                    month.afterDays = this.fillAfterDays(month.days[month.days.length - 1], afterCount);
                }

                let arr = Object.values(_months);
                return arr;
            },

            // 切换器按钮禁用状态
            disabledPrevMonth() {
                const yearMonthBefore = this.days.filter((day) => {
                    return (day.year === this.yearMonth.year && day.month < this.yearMonth.month) || day.year < this.yearMonth.year;
                });
                return yearMonthBefore.length <= 0;
            },

            // 切换器按钮禁用状态
            disabledNextMonth() {
                const yearMonthAfter = this.days.filter((day) => {
                    return (day.year === this.yearMonth.year && day.month > this.yearMonth.month) || day.year > this.yearMonth.year;
                });
                return yearMonthAfter.length <= 0;
            },

            // 切换器按钮禁用状态
            disabledPrevYear() {
                const yearMonthBefore = this.days.filter((day) => {
                    return (day.year === this.yearMonth.year - 1 && day.month < this.yearMonth.month) || day.year < this.yearMonth.year - 1;
                });
                return yearMonthBefore.length <= 0;
            },

            // 切换器按钮禁用状态
            disabledNextYear() {
                const yearMonthAfter = this.days.filter((day) => {
                    return (day.year === this.yearMonth.year + 1 && day.month > this.yearMonth.month) || day.year > this.yearMonth.year + 1;
                });
                return yearMonthAfter.length <= 0;
            },

            // 是否显示月份切换器
            showMonthSwitcher() {
                return this.switchMode === "month" || this.switchMode === "year-month";
            },

            // 是否显示年份切换器
            showYearSwitcher() {
                return this.switchMode === "year-month";
            },

            // 需要根据 firstDayOfWeek 来计算星期的顺序
            weekOrder() {
                let weekOrder = [];
                let before = this.week.slice(this.firstDayOfWeek);
                let after = this.week.slice(0, this.firstDayOfWeek);
                weekOrder = [...before, ...after];
                return weekOrder;
            },

            // 禁用日期列表
            disabledList() {
                return this.disabledDate.map((item) => {
                    const date = this.formatDate(item);
                    return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
                });
            },
        },
        watch: {
            // 监听开始日期变化
            fmtStartDate() {
                // 重新初始化
                this.init();
            },

            // 监听结束日期变化
            fmtEndDate() {
                // 重新初始化
                this.init();
            },

            // 监听显示状态
            async show(val) {
                // 设置对应的状态类名
                if (val) {
                    this.isShow = val;

                    await this.$nextTick();
                    await this.sleep(20);

                    // 获取滚动视图的布局信息
                    await this.getScrollViewRect();

                    // 获取滚动内容的布局信息
                    await this.getScrollCententRect();

                    // 获取月布局信息
                    await this.getMonthRects();

                    // 滚动到指定的年月
                    this.scrollToYearMonth(this.yearMonth.date);

                    this.status = "before-show";
                    await this.$nextTick();
                    await this.sleep(20);
                    this.status = "to-show";
                } else {
                    this.status = "before-hide";
                    await this.$nextTick();
                    await this.sleep(20);
                    this.status = "to-hide";
                }
            },
        },
        async mounted() {
            // 初始化IDs
            this.initIDs();

            // 初始化
            this.init();
        },
        methods: {
            // 初始化IDs
            initIDs() {
                this.scrollViewId = `PureCalendarScrollView_${Date.now()}_${this.randomString()}`;
                this.scrollContentId = `PureCalendarScrollContent_${Date.now()}_${this.randomString()}`;
            },

            // 初始化
            async init() {
                // 初始化显示状态
                if (this.poppable) {
                    this.isShow = this.show;
                    this.status = this.show ? "show" : "hide";
                } else {
                    this.isShow = true;
                    this.status = "show";
                }

                // 生成数据
                this.initData();

                // 默认展示的年月
                this.updateYearMonth(this.formatDate(this.showDate));

                await this.$nextTick();
                await this.sleep();

                // 获取滚动视图的布局信息
                await this.getScrollViewRect();

                // 获取滚动内容的布局信息
                await this.getScrollCententRect();

                // 获取月布局信息
                await this.getMonthRects();

                // 滚动到指定的年月
                this.scrollToYearMonth(this.yearMonth.date);
            },

            // 生成数据
            initData() {
                let days = [];

                // 结束日期不能小于开始日期
                if (this.fmtEndDate < this.fmtStartDate) {
                    console.error("结束日期不能小于开始日期");
                    return;
                }

                // 从开始日期开始
                let currentDate = new Date(this.fmtStartDate);

                // 遍历到结束日期
                while (currentDate <= this.fmtEndDate) {
                    let year = currentDate.getFullYear(); // 年
                    let month = currentDate.getMonth() + 1; // 月
                    let day = currentDate.getDate(); // 日
                    let str = `${year}-${month}-${day}`; // 字符串

                    // 查找现有数据，尽量不动现有数据
                    let findDay = this.days.find((item) => item?.str === str);

                    // 添加数据
                    if (findDay) days.push(findDay);
                    else days.push(this.createDayData(currentDate));

                    // 日期加一天
                    currentDate.setDate(currentDate.getDate() + 1);
                }

                // 补齐第一个月的前面的天数
                days = this.fillFirstMonthBeforeDays(days);

                // 补齐最后一个月后面的天数
                days = this.fillLastMonthAfterDays(days);

                // 赋值
                this.days = days;

                // 更新样式
                this.updateStyles();
            },

            // 点击事件
            dayClick(day) {
                // 只读模式
                if (this.readonly) return;

                // 禁用项
                if (day.disabled) return;

                // 不在范围内
                if (!day.inStartEnd) return;

                // 查找现有数据
                let index = this.days.findIndex((item) => item?.str === day.str);
                if (index < 0) return;

                // 单选
                if (this.mode === "single") {
                    // 当前选中状态
                    const isSelected = day.selected;

                    // 不可取消
                    if (!this.cancelable && isSelected) return;

                    // 可取消
                    this.days.forEach((item) => {
                        if (item?.str === day.str) {
                            item.selected = !item.selected;
                        } else {
                            item.selected = false;
                        }
                    });

                    // 更新样式
                    this.updateStyles();

                    // 提交事件
                    this.$emit("change", this.getSelected());
                    return;
                }

                // 多选
                if (this.mode === "multiple") {
                    // 最多选择无限制
                    if (this.maxRange === undefined || this.maxRange === null) {
                        day.selected = !day.selected;

                        // 更新样式
                        this.updateStyles();

                        // 提交事件
                        this.$emit("change", this.getSelected());
                        return;
                    }

                    // 最多选择限制
                    const selectedDates = this.getSelected();

                    // 取消选中
                    if (day.selected) {
                        day.selected = !day.selected;

                        // 更新样式
                        this.updateStyles();

                        // 提交事件
                        this.$emit("change", this.getSelected());
                        return;
                    }

                    // 新增选中
                    // 未达到限制
                    if (selectedDates.length < this.maxRange) {
                        day.selected = !day.selected;

                        // 更新样式
                        this.updateStyles();

                        // 提交事件
                        this.$emit("change", this.getSelected());
                        return;
                    }

                    // 达到了限制
                    this.$emit("outMaxRange");
                }

                // 区间
                if (this.mode === "range") {
                    // 第一次点击，选择的是区间开始
                    if (this.range[0] === undefined) {
                        this.range[0] = index;
                        this.days.forEach((item) => {
                            if (item?.str === day.str) {
                                item.selected = true;
                            } else {
                                item.selected = false;
                            }
                        });

                        // 更新样式
                        this.updateStyles();

                        // 提交事件
                        this.$emit("change", this.getSelected());

                        return;
                    }

                    // 第二次点击，选择的是区间结束
                    this.range[1] = index;

                    // 有可能结束的下标在开始下标之前，所以需要判断
                    let startIndex = this.range[0];
                    let endIndex = this.range[1];
                    if (startIndex > endIndex) {
                        let temp = startIndex;
                        startIndex = endIndex;
                        endIndex = temp;
                    }

                    // 最多选择无限制
                    if (this.maxRange === undefined || this.maxRange === null) {
                        // 选中区间日期
                        for (let i = 0; i < this.days.length; i++) {
                            if (i >= startIndex && i <= endIndex) {
                                this.days[i].selected = true;
                            } else {
                                this.days[i].selected = false;
                            }
                        }

                        // 清除本次区间选择
                        this.range = [];

                        // 更新样式
                        this.updateStyles();

                        // 提交事件
                        this.$emit("change", this.getSelected());
                        return;
                    }

                    // 最多选择限制
                    const selectedDatesCount = endIndex - startIndex + 1;

                    // 未达到限制
                    if (selectedDatesCount <= this.maxRange) {
                        // 选中区间日期
                        for (let i = 0; i < this.days.length; i++) {
                            if (i >= startIndex && i <= endIndex) {
                                this.days[i].selected = true;
                            } else {
                                this.days[i].selected = false;
                            }
                        }

                        // 清除本次区间选择
                        this.range = [];

                        // 更新样式
                        this.updateStyles();

                        // 提交事件
                        this.$emit("change", this.getSelected());
                        return;
                    }

                    // 达到了限制
                    if (selectedDatesCount > this.maxRange) {
                        this.$emit("outMaxRange");
                    }
                }
            },

            // 是否在开始日期-结束日期区间内
            isInRange(date) {
                // 只比较到日
                let dayDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
                let startDate = new Date(this.fmtStartDate.getFullYear(), this.fmtStartDate.getMonth(), this.fmtStartDate.getDate());
                let endDate = new Date(this.fmtEndDate.getFullYear(), this.fmtEndDate.getMonth(), this.fmtEndDate.getDate());
                return dayDate >= startDate && dayDate <= endDate;
            },

            // 更新样式
            updateStyles() {
                this.days.forEach((day, index) => {
                    const classes = [];
                    // 未选中
                    if (!day.selected) {
                        classes.push("pure-calendar-day-unselected");
                    }

                    // 选中了
                    if (day.selected) {
                        classes.push("pure-calendar-day-selected");

                        // 前后
                        let beforeDay = this.days[index - 1];
                        let afterDay = this.days[index + 1];

                        // 选中项之间
                        if (beforeDay?.selected && afterDay?.selected) classes.push("pure-calendar-day-selected-middle");
                        else {
                            // 前面没有选中项
                            if (!beforeDay?.selected) classes.push("pure-calendar-day-selected-start");
                            // 后面没有选中项
                            if (!afterDay?.selected) classes.push("pure-calendar-day-selected-end");
                        }
                    }

                    // 禁用
                    if (day.disabled) {
                        classes.push("pure-calendar-day-disabled");
                    }

                    // 范围内外
                    if (day.inStartEnd) {
                        classes.push("pure-calendar-day-in-start-end");
                    } else {
                        classes.push("pure-calendar-day-out-start-end");
                    }

                    day.classes = classes;
                });
            },

            // 获取选中项
            getSelected() {
                return this.days.filter((item) => item.selected && !item.disabled);
            },

            // 创建天数据
            createDayData(date) {
                return {
                    selected: this.isSelected(date), // 选中状态
                    disabled: this.isDisabled(date), // 禁用状态
                    date: date, // Date 对象
                    year: date.getFullYear(), // 年
                    month: date.getMonth() + 1, // 月
                    day: date.getDate(), // 日
                    week: date.getDay(), // 星期
                    str: `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`, // 字符串
                    inStartEnd: this.isInRange(date), // 是否在范围内
                };
            },

            // 是否禁用
            isDisabled(date) {
                const dateStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
                return this.fmtDisabledDate.includes(dateStr);
            },

            // 判断是否选中
            isSelected(date) {
                const dateStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
                return this.fmtDefaultDate.includes(dateStr);
            },

            // 更新展示的年月
            updateYearMonth(date) {
                const year = date?.getFullYear();
                const month = date.getMonth() + 1;
                const str = `${date?.getFullYear()}年${date.getMonth() + 1}月`;
                this.yearMonth.date = date;
                this.yearMonth.year = year;
                this.yearMonth.month = month;
                this.yearMonth.str = str;
            },

            // 补齐第一个月前面的天数
            fillFirstMonthBeforeDays(days) {
                // 第一个月的第一天
                const firstDay = days[0];

                // 第一个月的第一天是几号
                const firstDayNo = firstDay.day;

                // 补齐天数
                for (let i = firstDayNo - 1; i > 0; i--) {
                    const newDate = new Date(firstDay.year, firstDay.month - 1, i);
                    days.unshift(this.createDayData(newDate));
                }

                return days;
            },

            // 补齐最后一个月后面的天数
            fillLastMonthAfterDays(days) {
                // 最后一个月的最后一天
                const lastDay = days[days.length - 1];

                // 最后一个月的最后一天是几号
                const lastDayNo = lastDay.day;

                // 最后一个月的总天数
                const lastDayTotal = new Date(lastDay.year, lastDay.month, 0).getDate();

                // 补齐天数
                for (let i = lastDayNo + 1; i <= lastDayTotal; i++) {
                    const newDate = new Date(lastDay.year, lastDay.month - 1, i);
                    days.push(this.createDayData(newDate));
                }

                return days;
            },

            // 补齐前面的格子
            fillBeforeDays(day, count) {
                let days = [];
                for (let i = 1; i <= count; i++) {
                    let newDate = new Date(day.year, day.month - 1, day.day);
                    newDate.setDate(newDate.getDate() - i);
                    const str = `${newDate?.getFullYear()}-${newDate.getMonth() + 1}-${newDate.getDate()}`;
                    let findDay = this.days.find((item) => item?.str === str);
                    if (findDay) days.unshift(findDay);
                    else days.unshift(this.createDayData(newDate));
                }
                return days;
            },

            // 补齐后面的格子
            fillAfterDays(day, count) {
                let days = [];
                for (let i = 1; i <= count; i++) {
                    let newDate = new Date(day.year, day.month - 1, day.day);
                    newDate.setDate(newDate.getDate() + i);
                    const str = `${newDate?.getFullYear()}-${newDate.getMonth() + 1}-${newDate.getDate()}`;
                    let findDay = this.days.find((item) => item?.str === str);
                    if (findDay) days.push(findDay);
                    else days.push(this.createDayData(newDate));
                }
                return days;
            },

            // 格式化日期
            formatDate(date) {
                // date 是函数类型
                if (typeof date === "function") {
                    date = date();
                }

                // date 是 Date 类型
                if (date instanceof Date) {
                    return date;
                }

                // date 是字符串类型
                if (typeof date === "string") {
                    return new Date(date.replace(/-/g, "/"));
                }

                // date 是数字类型
                if (typeof date === "number") {
                    // 如果是 13 位数字，则是时间戳
                    if (date.toString().length === 13) {
                        return new Date(date);
                    }
                    // 如果是 10 位数字，则是时间戳的秒数
                    if (date.toString().length === 10) {
                        return new Date(date * 1000);
                    }
                    return new Date(date);
                }

                return new Date(date);
            },

            // 上月
            handlePrevMonth() {
                const date = this.yearMonth.date;
                const dateYear = date?.getFullYear();
                const dateMonth = date.getMonth();
                const newDate = new Date(dateYear, dateMonth - 1);

                // 更新展示的年月
                this.updateYearMonth(newDate);

                // 滚动到指定的年月
                this.scrollToYearMonth(this.yearMonth.date);
            },

            // 下月
            handleNextMonth() {
                const date = this.yearMonth.date;
                const dateYear = date?.getFullYear();
                const dateMonth = date.getMonth();
                const newDate = new Date(dateYear, dateMonth + 1);

                // 更新展示的年月
                this.updateYearMonth(newDate);

                // 滚动到指定的年月
                this.scrollToYearMonth(this.yearMonth.date);
            },

            // 上年
            handlePrevYear() {
                const date = this.yearMonth.date;
                const dateYear = date?.getFullYear();
                const dateMonth = date.getMonth();
                const newDate = new Date(dateYear - 1, dateMonth);

                // 更新展示的年月
                this.updateYearMonth(newDate);

                // 滚动到指定的年月
                this.scrollToYearMonth(this.yearMonth.date);
            },

            // 下年
            handleNextYear() {
                const date = this.yearMonth.date;
                const dateYear = date?.getFullYear();
                const dateMonth = date.getMonth();
                const newDate = new Date(dateYear + 1, dateMonth);

                // 更新展示的年月
                this.updateYearMonth(newDate);

                // 滚动到指定的年月
                this.scrollToYearMonth(this.yearMonth.date);
            },

            // 获取滚动视图的布局信息
            getScrollViewRect() {
                return new Promise(async (resolve) => {
                    const id = `#${this.scrollViewId}`;
                    const query = uni.createSelectorQuery().in(this);
                    query
                        .select(id)
                        .boundingClientRect((rect) => {
                            this.scrollViewRect = rect;
                            resolve(rect);
                        })
                        .exec();
                });
            },

            // 获取滚动内容的布局信息
            getScrollCententRect() {
                return new Promise(async (resolve) => {
                    const id = `#${this.scrollContentId}`;
                    const query = uni.createSelectorQuery().in(this);
                    query
                        .select(id)
                        .boundingClientRect((rect) => {
                            this.scrollContentRect = rect;
                            resolve(rect);
                        })
                        .exec();
                });
            },

            // 获取月布局信息
            getMonthRects() {
                return new Promise(async (resolve) => {
                    const id = `#${this.scrollContentId}`;
                    const selector = `${id} .pure-calendar-month-wrapper`;
                    const query = uni.createSelectorQuery().in(this);
                    query
                        .selectAll(selector)
                        .boundingClientRect((rects) => {
                            this.monthRects = rects || [];
                            resolve(rects);
                        })
                        .exec();
                });
            },

            // 滚动事件
            handleScroll(e) {
                // 更新滚动距离
                this.scrollTop = e.detail.scrollTop;

                // 滚动后计算年月
                this.computeYearMonth();
            },

            // 滚动后计算年月
            async computeYearMonth() {
                // 正在计算
                if (this.isComputing) {
                    this.isNeedCompteNext = true;
                    return;
                }

                // 更新计算状态
                this.isComputing = true;

                // 从后向前计算
                for (let i = this.monthRects.length - 1; i >= 0; i--) {
                    const monthRect = this.monthRects[i];
                    if (!monthRect || !this.scrollContentRect) continue;
                    if (this.scrollTop >= monthRect.top - this.scrollContentRect.top + (this.scrollViewRect?.height || 0) * 0.5) {
                        this.updateYearMonth(new Date(this.months[i]?.year, this.months[i]?.month));
                        break;
                    }
                }

                // 等待一会再进行下次循环
                await this.sleep();
                this.isComputing = false;
                if (this.isNeedCompteNext) {
                    this.isNeedCompteNext = false;
                    this.computeYearMonth();
                }
            },

            // 滚动到指定年月
            scrollToYearMonth(date) {
                if (!date) return;
                const year = date.getFullYear();
                const month = date.getMonth() + 1;
                const index = this.months.findIndex((_month) => _month.year === year && _month.month === month);
                if (index < 0) return;
                const monthRect = this.monthRects[index];
                if (!monthRect || !this.scrollContentRect) return;
                this.scrollToTop = monthRect.top - this.scrollContentRect.top;
            },

            // 格式化水印
            getWatermark(month) {
                if (typeof this.formatWatermark === "function") {
                    return this.formatWatermark(month);
                }
                return `${month?.month}`;
            },

            // 格式化月标题
            getMonthTitle(month) {
                if (typeof this.formatMonthTitle === "function") {
                    return this.formatMonthTitle(month);
                }
                return `${month?.year}年${month?.month}月`;
            },

            // 格式化日
            getDay(day) {
                if (typeof this.formatDay === "function") {
                    return this.formatDay(day);
                }
                return `${day?.day}`;
            },

            // 格式化副标题
            getSubtitle(subtitle) {
                if (typeof this.formatSubtitle === "function") {
                    return this.formatSubtitle(subtitle);
                }
                return `${subtitle?.year}年${subtitle?.month}月`;
            },

            // 遮罩点击事件
            handleOverlayClose() {
                // 点击遮罩不可关闭
                if (this.stopCloseOnClickOverlay) return;
                this.$emit("close");
            },

            // 关闭按钮点击事件
            handleClose() {
                this.$emit("close");
            },

            // 过渡结束事件
            handleTransitionEnd() {
                // 更新状态
                if (this.status === "to-show") {
                    this.status = "show";
                    this.isShow = true;
                    return;
                }
                if (this.status === "to-hide") {
                    this.status = "hide";
                    this.isShow = false;
                    return;
                }
            },

            // 确认
            handleConfirm() {
                this.$emit("confirm", this.getSelected());
            },

            // 同步延时
            sleep(time = 100) {
                return new Promise((resolve) => {
                    let timer = setTimeout(() => {
                        clearTimeout(timer);
                        resolve();
                    }, time);
                });
            },

            // 生成一个36位的随机字符串
            randomString() {
                return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
            },
        },
    };
</script>

<style>
    /* 隐藏滚动条 */
    ::-webkit-scrollbar {
        width: 0;
        height: 0;
    }

    ::-webkit-scrollbar-thumb {
        width: 0;
        height: 0;
    }
</style>

<style scoped>
    @import "./style.css";
</style>
